#pragma once

#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QIcon>
#include <QString>
#include <QUuid>

#include "base.qpb.h"
#include "file.qpb.h"
#include "friend.qpb.h"
#include "gateway.qpb.h"
#include "message_storage.qpb.h"
#include "message_transmit.qpb.h"
#include "notify.qpb.h"
#include "speech_recognition.qpb.h"
#include "user.qpb.h"

namespace model
{
//////////////////////////////////////////////////////
/// 工具函数
//////////////////////////////////////////////////////
static inline QString getFileName(const QString &path)
{
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}

// 封装日志打印宏
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))

// 使用qDebug打印时自动加上TAG
#define LOG() qDebug().noquote() << TAG

static inline QString formatTime(int64_t timestamp)
{
    // 把时间戳转换成QDateTime
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    // 把QDateTime对象转换成“格式时间”
    return dateTime.toString("MM-dd HH:mm:ss");
}

// 通过这个函数获得 秒级 的时间
static inline int64_t getTime() { return QDateTime::currentSecsSinceEpoch(); }

// 根据QByteArray，转换成QIcon
static inline QIcon makeIcon(const QByteArray &byteArray)
{
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}

// 从指定文件中读取所有的二进制内容，返回一个QByteArray
static inline QByteArray loadFileToByteArray(const QString &path)
{
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if (!ok)
    {
        LOG() << "文件打开失败！";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}

// 把QByteArray中的内容写入到某个指定的文件里
static inline void writeByteArrayToFile(const QString &path, const QByteArray &content)
{
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if (!ok)
    {
        LOG() << "文件打开失败！";
        return;
    }
    file.write(content);
    file.flush();
    file.close();
}

//////////////////////////////////////////////////////
/// 用户信息
//////////////////////////////////////////////////////

class UserInfo
{
  public:
    QString userId      = ""; // 用户编号
    QString nickname    = ""; // 用户昵称
    QString description = ""; // 用户签名
    QString phone       = ""; // 手机号码
    QIcon avatar;             // 用户头像

    void load(const MicroIMS::UserInfo &userInfo)
    {
        this->userId      = userInfo.userId();
        this->nickname    = userInfo.nickname();
        this->description = userInfo.description();
        this->phone       = userInfo.phone();
        if (userInfo.avatar().isEmpty())
        {
            // 使用默认头像
            this->avatar = QIcon("");
        }
        else
        {
            this->avatar = makeIcon(userInfo.avatar());
        }
    }
};

//////////////////////////////////////////////////////
/// 消息信息
//////////////////////////////////////////////////////
enum MessageType
{
    TEXT_TYPE,  // 文本消息
    IMAGE_TYPE, // 图片消息
    FILE_TYPE,  // 文件消息
    SPEECH_TYPE // 语音消息
};

class Message
{
  public:
    QString messageId       = "";        // 消息编号
    QString chatSessionId   = "";        // 消息所属会话编号
    QString time            = "";        // 消息的时间 -- "10-27 21:00:00"
    MessageType messageType = TEXT_TYPE; // 消息类型
    UserInfo sender;                     // 发送者信息
    QByteArray content;                  // 消息的正文内容
    QString fileId   = "";               // 文件的身份标识 -- 当消息类型为 文件、图片、语音 时有效；为 文本 时则为
    QString fileName = "";               // 文件名称 -- 当消息类型为 文件、消息 时有效；为其他消息时为 ""

    // 此处 extraInfo 仅在消息类型为 文件 时作为 文件名 补充
    static Message makeMessage(MessageType messageType, const QString &chatSessionId, const UserInfo &sender,
                               const QByteArray &content, const QString &extraInfo)
    {
        if (messageType == TEXT_TYPE)
        {
            return makeTextMessage(chatSessionId, sender, content);
        }
        else if (messageType == IMAGE_TYPE)
        {
            return makeImageMessage(chatSessionId, sender, content);
        }
        else if (messageType == FILE_TYPE)
        {
            return makeFileMessage(chatSessionId, sender, content, extraInfo);
        }
        else if (messageType == SPEECH_TYPE)
        {
            return makeSpeechMessage(chatSessionId, sender, content);
        }
        else
        {
            // 未知消息类型
            return Message();
        }
    }

    void load(const MicroIMS::MessageInfo &messageInfo)
    {
        this->messageId     = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time          = formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());

        // 设置消息类型
        auto type = messageInfo.message().messageType();
        if (type == MicroIMS::MessageTypeGadget::MessageType::STRING)
        {
            this->messageType = TEXT_TYPE;
            this->content     = messageInfo.message().stringMessage().content().toUtf8();
        }
        else if (type == MicroIMS::MessageTypeGadget::MessageType::IMAGE)
        {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent())
            {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId())
            {
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        }
        else if (type == MicroIMS::MessageTypeGadget::MessageType::FILE)
        {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents())
            {
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if (messageInfo.message().fileMessage().hasFileId())
            {
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        }
        else if (type == MicroIMS::MessageTypeGadget::MessageType::SPEECH)
        {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents())
            {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId())
            {
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        }
        else
        {
            LOG() << "非法的消息类型！type=" << type;
        }
    }

  private:
    static QString makeId() { return "M" + QUuid::createUuid().toString().sliced(25, 12); }

    static Message makeTextMessage(const QString &chatSessionId, const UserInfo &sender, const QByteArray &content)
    {
        Message message;
        message.messageId     = makeId();
        message.chatSessionId = chatSessionId;
        message.sender        = sender;
        message.time          = formatTime(getTime());
        message.content       = content;
        message.messageType   = TEXT_TYPE;
        message.fileId        = ""; // 不使用
        message.fileName      = ""; // 不使用
        return message;
    }

    static Message makeImageMessage(const QString &chatSessionId, const UserInfo &sender, const QByteArray &content)
    {
        Message message;
        message.messageId     = makeId();
        message.chatSessionId = chatSessionId;
        message.sender        = sender;
        message.time          = formatTime(getTime());
        message.content       = content;
        message.messageType   = IMAGE_TYPE;
        message.fileId        = ""; // fileId 后续再进一步设置
        message.fileName      = ""; // 不使用
        return message;
    }

    static Message makeFileMessage(const QString &chatSessionId, const UserInfo &sender, const QByteArray &content,
                                   const QString &fileName)
    {
        Message message;
        message.messageId     = makeId();
        message.chatSessionId = chatSessionId;
        message.sender        = sender;
        message.time          = formatTime(getTime());
        message.content       = content;
        message.messageType   = FILE_TYPE;
        message.fileId        = ""; // fileId 后续再进一步设置
        message.fileName      = fileName;
        return message;
    }

    static Message makeSpeechMessage(const QString &chatSessionId, const UserInfo &sender, const QByteArray &content)
    {
        Message message;
        message.messageId     = makeId();
        message.chatSessionId = chatSessionId;
        message.sender        = sender;
        message.time          = formatTime(getTime());
        message.content       = content;
        message.messageType   = SPEECH_TYPE;
        message.fileId        = ""; // fileId 后续再进一步设置
        message.fileName      = ""; // 不使用
        return message;
    }
};

// //////////////////////////////////////////////////////
// /// 会话信息
// //////////////////////////////////////////////////////

class ChatSessionInfo
{
  public:
    QString chatSessionId   = ""; // 会话编号
    QString chatSessionName = ""; // 会话名字 -- 如果会话是单聊，名字就是对方的昵称；如果是群聊，名字就是群聊名称
    Message lastMessage;          // 表示最新消息
    QIcon avatar;                 // 会话头像 -- 如果会话是单聊，头像就是对方的头像；如果是群聊，头像就是群聊头像
    QString userId = "";          // 仅用于单聊，表示对方的用户id；群聊设为 ""

    void load(const MicroIMS::ChatSessionInfo &chatSessionInfo)
    {
        this->chatSessionId   = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        if (chatSessionInfo.hasSingleChatFriendId())
        {
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if (chatSessionInfo.hasPrevMessage())
        {
            lastMessage.load(chatSessionInfo.prevMessage());
        }
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty())
        {
            // 已经有头像了，直接设置这个头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        }
        else
        {
            // 如果没有头像，则根据当前会话是单聊还是群聊设置默认头像
            if (userId != "")
            {
                // 单聊
                this->avatar = QIcon(":/resource/image/defaultAvatar.png");
            }
            else
            {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }
    }
};

} // namespace model
